<?php

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
    name: 'make:entity-repository',
    description: 'create repository for entity',
)]
class MakeEntityRepositoryCommand extends Command
{
    private string $repositoryDir;
    private string $repositoryMsgDir = 'src/Repository/';
    private string $entityDir;
    private string $entityMsgDir = "src/Entity/";

    public function __construct()
    {
        parent::__construct();
        $this->entityDir = dirname(__DIR__) . "/Entity/";
        $this->repositoryDir = dirname(__DIR__) . "/Repository/";
        if (!file_exists($this->repositoryDir)) {
            mkdir($this->repositoryDir);
        }
    }

    protected function configure(): void
    {
        $this
            ->addArgument('file', InputArgument::OPTIONAL, 'the entity name')
            ->setHelp("create repository for entity after 'doctrine:mapping:import', 'make:entity --regenerate App'");
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $createRepository = [];
        try {
            $file = $input->getArgument('file');
            if ($file) {
                $entityFilePath = $this->entityDir . $file . ".php";
                if (!file_exists($entityFilePath)) {
                    $io->error($this->entityMsgDir . $file . ".php is not exists");
                    return Command::FAILURE;
                }
                $repositoryFilePath = $this->createRepositoryFile($file);
                $io->note($repositoryFilePath . ' has been created.');
                $this->addRepositoryForEntityFile($file);
            } else {
                $fn = dir($this->entityDir);
                while ($subFile = $fn->read()) {
                    if ($subFile != "." && $subFile != ".." && !str_starts_with($subFile,
                            '.') && is_file($this->entityDir . $subFile)) {
                        $basename = basename($subFile, '.php');
                        $repositoryFilePath = $this->createRepositoryFile($basename);
                        if ($repositoryFilePath) {
                            $createRepository[] = $repositoryFilePath;
                        }
                        $this->addRepositoryForEntityFile($basename);
                    }
                }
                if (count($createRepository) > 0) {
                    $io->note($createRepository);
                }
                $io->success('All Repository files has been created!');
            }
            return Command::SUCCESS;
        } catch (\Exception $e) {
            $io->error($e->getMessage());
            $io->error($e->getTrace());
            return Command::FAILURE;
        }
    }

    /**
     * @param string $file
     * @return string
     */
    private function createRepositoryFile(string $file): string
    {
        $repositoryFilePath = $this->repositoryDir . $file . "Repository.php";
        if (!file_exists($repositoryFilePath)) {
            $string = <<<EOF
<?php

namespace App\Repository;

use App\Entity\\{$file};
use Doctrine\Persistence\ObjectManager;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;

class {$file}Repository extends ServiceEntityRepository
{
    private ObjectManager \$manager;
    
    public function __construct(ManagerRegistry \$registry)
    {
        parent::__construct(\$registry, {$file}::class);
        \$this->manager = \$registry->getManager();
    }
}

EOF;
            file_put_contents($repositoryFilePath, $string);
            return $this->repositoryMsgDir . $file . "Repository.php";
        }
        return "";
    }

    private function addRepositoryForEntityFile(string $file)
    {
        $entityFilePath = $this->entityDir . $file . ".php";
        $string = file_get_contents($entityFilePath);
        $tag = "@ORM\Entity(repositoryClass={$file}Repository::class)";
        $find = "use Doctrine\\ORM\\Mapping as ORM;";
        $repository = "\r\nuse App\\Repository\\{$file}Repository;";
        if (!str_contains($string, $tag)) {
            $string = str_replace($find, $find . $repository, $string);
            $string = str_replace("@ORM\Entity", $tag, $string);
            file_put_contents($entityFilePath, $string);
        }
    }
}
